﻿package Core 
{
	import com.junkbyte.console.Cc;

	import flash.display.BitmapData;
	import flash.events.ProgressEvent;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequestHeader;
	import flash.net.URLRequestMethod;
	import flash.utils.ByteArray;
	
	import Common.Constants;
	import Common.Preloader;
	import Common.JPEGAsyncCompleteEvent;
	import Common.JPEGAsyncEncoder;
	import Events.ImageProgressEvent;
	import Events.ImageEvent;
	
	import flash.display.Bitmap;
	import flash.display.Loader;	
	import flash.events.DataEvent;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.net.FileReference;
	import flash.net.URLRequest;
	/**
	 * ...
	 * @author Serg de Adelantado
	 */	
	public class LocalImage extends ImageContainer 
	{		
		private var FFile:FileReference;		
		private var FBytesLoader:Loader;
		private var FIsLoading:Boolean;		
		//Uploading
		private var FEncoder:JPEGAsyncEncoder;
		private var FUploader:URLLoader;
		private var FBitmapToUpload:Bitmap;
		private var FEncoded:ByteArray;
		
		public function LocalImage(AWidth:int, AHeight:int)
		{
			super(AWidth, AHeight);
			FEncoder = new JPEGAsyncEncoder(Constants.IMAGE_QUALITY);
			IsLocal = true;
			FIsLoading = false;
		}
		
		override public function Load():void
		{		
			if (FFile)
			{
				if (!FIsLoading)
				{
					FFile.load();
					FIsLoading = true;
					FFile.addEventListener(Event.COMPLETE, OnLocalFileLoaded);
				}
			}
			else
				Cc.errorch('Local image', 'Can not load image: FileReference was not assigned');
		}
		
		protected function OnLocalFileLoaded(e:Event):void
		{
			e.target.removeEventListener(Event.COMPLETE, OnLocalFileLoaded);
			FIsLoading = false;
			FBytesLoader = new Loader();
			FBytesLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, OnImageLoaded);
			FBytesLoader.loadBytes(e.target.data);
		}
		
		private function OnImageLoaded(e:Event):void 
		{
			e.target.removeEventListener(Event.COMPLETE, OnImageLoaded);
			ProcessBitmap(Bitmap(e.target.content));
		}
		
		override protected function ProcessBitmap(ABitmap:Bitmap):void 
		{
			FBitmapToUpload = Resize(ABitmap, new Point(Constants.IMAGE_SIZE, Constants.IMAGE_SIZE));
			FBitmap = Resize(FBitmapToUpload, FSize);
			ABitmap.bitmapData.dispose();				
			FBitmap.x = (FSize.x - FBitmap.width) / 2;
			FBitmap.y = (FSize.y - FBitmap.height) / 2;
			addChild(FBitmap);
			addChild(FDeleter);
			addChild(FTools);	
			addChild(FSelector);
			FBytesLoader.contentLoaderInfo.bytes.clear();
			FBytesLoader.unloadAndStop();
			FBytesLoader = null;
			FIsLoaded = true;
			dispatchEvent(new ImageEvent(ImageEvent.IMAGE_LOADED));
		}
		
		private function Resize(ABitmap:Bitmap, ASize:Point):Bitmap
		{
			var vBitmap:Bitmap = ABitmap;
			var vResultBitmap:Bitmap;
			vBitmap.smoothing = true;
			var vOriginal:Point = new Point(vBitmap.width, vBitmap.height);						
			ImageUtils.Resize(vBitmap, ASize.x - 5, ASize.y - 5);			
			var vMatrix:Matrix = new Matrix();
			vMatrix.scale(vBitmap.width / vOriginal.x, vBitmap.height / vOriginal.y);
			var vResult:BitmapData = new BitmapData(vBitmap.width, vBitmap.height, false);
			vResult.draw(vBitmap, vMatrix);
			vResultBitmap = new Bitmap(vResult);
			vMatrix = null;
			return vResultBitmap;
		}
			
		override public function UploadImage():void
		{			
			if (FFile && FIsLocal)			
				Encode();			
			else
				super.UploadImage();
		}	
		
		protected function Encode():void
		{
			FEncoder.addEventListener(JPEGAsyncCompleteEvent.JPEGASYNC_COMPLETE, OnEncodeComplete);
			FEncoder.addEventListener(ProgressEvent.PROGRESS, OnEncodeProgress);
			FEncoder.encode(FBitmapToUpload.bitmapData);
		}
		
		private function OnEncodeProgress(e:ProgressEvent):void 
		{
			trace(e.bytesLoaded, e.bytesTotal);
			dispatchEvent(new ImageProgressEvent(ImageProgressEvent.PROGRESS, e.bytesLoaded / e.bytesTotal));
		}
		
		private function OnEncodeComplete(e:JPEGAsyncCompleteEvent):void 
		{
			FEncoded = e.ImageData;
			DoUpload();
		}
		
		private function DoUpload():void 
		{
			FPreloader = new Preloader();
			Enabled = false;
			addChild(FPreloader);
			FPreloader.x = (width - FPreloader.width) / 2;
			FPreloader.y = (height / 2 - FPreloader.height) / 2;
			var vVars:String = '?name=' + FID;
			vVars += '&owner_type=' + FOwnerType;
			vVars += '&rotation=' + int(-FRotation);
			FUploader = new URLLoader();
			FUploader.addEventListener(Event.COMPLETE, OnImageUploaded);
			FUploader.addEventListener(IOErrorEvent.IO_ERROR, OnIOError);
			FUploader.addEventListener(ProgressEvent.PROGRESS, OnUploadingProgress);				
			var vURLRequest:URLRequest = new URLRequest(Constants.IMAGE_UPLOADER + vVars);			
			vURLRequest.contentType = "binary/octet-stream";
			vURLRequest.method = URLRequestMethod.POST;
			vURLRequest.data = FEncoded;
			vURLRequest.requestHeaders.push(new URLRequestHeader("Content-type", "application/octet-stream"));				
			FUploader.dataFormat = URLLoaderDataFormat.BINARY;
			FUploader.load(vURLRequest);
			Cc.logch('Image uploading', 'Starting uploading');
		}
		
		private function RemoveFileListeners():void
		{
			FUploader.removeEventListener(IOErrorEvent.IO_ERROR, OnIOError);
			FUploader.removeEventListener(Event.COMPLETE, OnImageUploaded);
			FUploader.removeEventListener(ProgressEvent.PROGRESS, OnUploadingProgress);
		}
		
		private function OnUploadingProgress(e:ProgressEvent):void 
		{			
			Cc.logch('Image uploading', 'Uploaded ' + Math.round(100 * e.bytesLoaded / e.bytesTotal) + ' %');
		}
		
		protected function OnIOError(e:IOErrorEvent):void 
		{
			RemoveFileListeners();
			Enabled = true;			
			removeChild(FPreloader);
			dispatchEvent(new ImageEvent(ImageEvent.UPDATE_ERROR));
			Cc.errorch('Image uploading', 'IO Error: ' + e.text);
		}
		
		protected function OnImageUploaded(e:Event):void 
		{			
			RemoveFileListeners();
			Enabled = true;
			IsLocal = false;
			FRotationToSend = 0;
			FOldType = FOwnerType;
			removeChild(FPreloader);
			Cc.logch('Image uploading', 'Response: ' + e.target.data);
			FBitmapToUpload.bitmapData.dispose();
			
			FEncoder.removeEventListener(JPEGAsyncCompleteEvent.JPEGASYNC_COMPLETE, OnEncodeComplete);
			FEncoder.removeEventListener(ProgressEvent.PROGRESS, OnEncodeProgress);
			FEncoder.ImageData.clear();
			FEncoder = null;
			
			dispatchEvent(new ImageEvent(ImageEvent.UPDATE_COMPLETE));					
		}
		
		override public function Destroy():void
		{
			if (FBitmapToUpload)			
				FBitmapToUpload.bitmapData.dispose();			
			super.Destroy();
		}
		
		public function set File(AFile:FileReference):void 
		{
			FFile = AFile;
		}
		
		public function set Encoder(AEncoder:JPEGAsyncEncoder):void 
		{
			//FEncoder = AEncoder;
		}
		
		public function get File():FileReference
		{
			return FFile;
		}
		
		public function get IsLoading():Boolean
		{
			return FIsLoading;
		}		
		
		override public function get TipText():String
		{
			var vResult:String;
			if(FIsLocal)
				vResult = File.name + '\n' + "<font color='" + '#666666' + "'>" + 
				'Локальный файл. Размер: ' + Number(File.size / 1024).toFixed() + ' Кб' + "</font>"  + '\n';			
			else
				vResult = "<font color='" + '#666666' + "'>" + 'Сетевой файл' + "</font>" + '\n';			
			return vResult;
		}
	}
}